﻿#include "operatordefinition.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QDebug>
#include <QTextDocumentFragment>

TransKind jsonValueToTransKind(QJsonValue value)
{
    if (value.isString()) {
        if(value.toString()=="0")
        {
            return STRONG;
        }

        if(value.toString()=="1")
        {
            return WEAK;
        }

        if(value.toString()=="2")
        {
            return SYNCHRO;
        }
    } else {
        switch (value.toInt()) {
        case 0:
            return STRONG;
        case 1:
            return WEAK;
        case 2:
            return SYNCHRO;
        }
    }
}

TransHistory jsonValueToTransHistory(QJsonValue value)
{
    if (value.isString()) {
        if(value.toString()=="0")
        {
            return RESTART;
        }

        if(value.toString()=="1")
        {
            return RESUME;
        }
    } else {
        switch (value.toInt()) {
        case 0:
            return RESTART;
        case 1:
            return RESUME;

        }
    }

}

QString Transition::condition() const
{
    return  QTextDocumentFragment::fromHtml(condition_).toPlainText();
}

void Transition::setCondition(const QString &condition)
{
    condition_ = condition.toHtmlEscaped();
}

QString Transition::actions() const
{
    return QTextDocumentFragment::fromHtml(actions_).toPlainText();
}

void Transition::setActions(const QString &actions)
{
    actions_ = actions.toHtmlEscaped();
}



StmModel::StmModel()
{

}

//void StmModel::loadOperatorFile(const QString &projectOid, const QString &projectPath, const QString &operatorFileName)
//{
//    m_operator.path=projectPath;
//    m_operator.projectOid=projectOid;

//    //加载操作符文件

//    QString filePath=projectPath+"/"+operatorFileName;
//    QFile file(filePath);
//    if(!file.open(QFile::ReadOnly| QIODevice::Text)){
//        qDebug()<<"loadOperatorSTM FILE "+operatorFileName+" failed";
//        return ;
//    }
//    QTextStream stream(&file);
//    QString xmlContent = stream.readAll();
//    file.close();
//    QDomDocument doc;
//    if(!doc.setContent(xmlContent)){
//        qDebug()<<"loadOperatorSTM FILE "+operatorFileName+" failed";
//        return ;
//    }

//    QDomElement root=doc.documentElement();//File节点
//    QDomNode declarationsNode=root.firstChild();

//    QDomElement operatorElement=declarationsNode.firstChildElement();
//    QString operatorName=operatorElement.attribute("name");
//    m_operator.name=operatorName;

//    QDomNode oidNode=operatorElement.namedItem("oid");
//    QString operatorOid=oidNode.toElement().attribute("value");
//    m_operator.oid=operatorOid;

//    QDomNode dataNode=operatorElement.namedItem("data");
//    QDomNodeList dataChildNodes=dataNode.childNodes();

//    for(int i=0;i<dataChildNodes.size();i++)
//    {
//        QDomElement item=dataChildNodes.at(i).toElement();

//        if(item.tagName()=="StateMachineRef")
//        {
//            QString stmName=item.attribute("name");
//            QString stmOid=item.attribute("oid");
//            QString pouFilePath=projectPath+"/"+item.attribute("filepath");

//            loadPOUXML(pouFilePath);

//            m_operator.stmList.append(stmOid);
//        }
//    }

//    addOperator(m_operator);
//}

//void StmModel::addOperator(const Operator &op)
//{
//    m_operator=op;
//}

void StmModel::init()
{

}

bool StmModel::removeDirectory(const QString &dirPath) {
    QDir dir(dirPath);
    if (!dir.exists()) {
        return false;
    }

    // 删除文件夹中的所有文件和子文件夹
    foreach (QFileInfo item, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries)) {
        if (item.isDir()) {
            // 递归删除子文件夹
            if (!removeDirectory(item.absoluteFilePath())) {
                return false;
            }
        } else {
            // 删除文件
            if (!QFile::remove(item.absoluteFilePath())) {
                return false;
            }
        }
    }

    // 删除空文件夹本身
    return dir.rmdir(dirPath);
}


void StmModel::addStateMachine(const QString& oid,const StateMachine &stm)
{
    m_stms.insert(oid,stm);
}

void StmModel::addState(const QString& oid,const State &state)
{
    m_states.insert(oid, state);
}

void StmModel::addTrans(const Transition &trans)
{
    m_trans.insert(trans.oid, trans);
}

StateMachine* StmModel::getStateMachine(const QString &stmId)
{
    return &m_stms[stmId];
}



State* StmModel::getState(const QString &oid)
{
    if (oid.isEmpty())
        return nullptr;

    return &m_states[oid];
}

Transition* StmModel::getTransition(const QString &oid)
{
    return &m_trans[oid];
}

//Operator *StmModel::getOperator(const QString &oid)
//{
//    return &m_operator;
//}

void StmModel::deleteStateMachine(const QString & oid)
{
    m_stms.remove(oid);
}

void  StmModel::deleteState(const QString & oid)
{
    m_states.remove(oid);
}

void  StmModel::deleteTransition(const QString & oid)
{
    m_trans.remove(oid);
}

//Operator StmModel::deleteOperator()
//{
//    m_operator=Operator();

//    return m_operator;
//}


//QList<StateMachineDefine::StateMachine*> OperatorModel::getStateMachineList()
//{
//    QMutexLocker locker(&mutex_);
//    StateMachineDefine::StateMachineMessageIO io(m_writer);
//    QList<QString> stmOids = io.getAllStateMachineOIDs();

//    QList<StateMachineDefine::StateMachine*> list;
//    for(const QString &id : stmOids)
//    {
//        list.append(getStateMachine(id));
//    }
//    return list;
//}

QList<Transition*> StmModel::getStateTransitionList(const QString & oid)
{
    State state = m_states.value(oid);

    QList<Transition*> list;
    for(const QString &id : state.trans_strong)
    {
        list.append(getTransition(id));
    }
    for(const QString &id : state.trans_weak)
    {
        list.append(getTransition(id));
    }
    for(const QString &id : state.trans_sync)
    {
        list.append(getTransition(id));
    }

    return list;

}

QString StmModel::getSTMID(const StateMachine &stm)
{
    return stm.scadeOid;
}

QString StmModel::getSTMID(const State &state)
{
    //TODO: check pointer
    auto *stm = getStateMachine(state.parentid);
    if (stm == nullptr)
        return QString();
    return getSTMID(*stm);
}

QString StmModel::getSTMID(const Transition &trans)
{
    auto *state = getState(trans.source);
    if (state == nullptr)
        return QString();
    return getSTMID(*state);
}

QStringList StmModel::getTransPriorList(const Transition& trans)
{
    State *STsource = getState(trans.source);
    if (!STsource) {
        return QStringList();
    }
    QVector<QString> STsourceStrong = STsource->trans_strong;
    QVector<QString> STsourceWeak = STsource->trans_weak;
    QVector<QString> STsourceSync = STsource->trans_sync;

    // 构建三种迁移的优先级列表
    QStringList StrongList, WeakList, SyncList;
    int prior = 0;

    // 根据源状态的迁移类型构建优先级列表
    for (int i = 0; i < STsourceStrong.size(); ++i) {
        StrongList.append(QString::number(++prior));
    }
    for (int i = 0; i < STsourceWeak.size(); ++i) {
        WeakList.append(QString::number(++prior));
    }
    for (int i = 0; i < STsourceSync.size(); ++i) {
        SyncList.append(QString::number(++prior));
    }

    // 根据迁移类型返回迁移优先级列表
    switch (trans.kind) {
    case STRONG:
        return StrongList;
    case WEAK:
        return WeakList;
    case SYNCHRO:
        return SyncList;
    }

    // default
    return QStringList(); // 或者根据需要返回其他值
}

void StmModel::setStms(QMap<QString, StateMachine> stms)
{
    m_stms=stms;
}

void StmModel::setStates(QMap<QString, State> states)
{
    m_states=states;
}

void StmModel::setTransitions(QMap<QString, Transition> trans)
{
    m_trans=trans;
}

//StateMachineDefine::StateMachine &STMModel::statemachine() {
//    getStateMachine(m_stm.oid);
//    return m_stm;
//}

//QMap<QString, StateMachineDefine::State> &STMModel::states() {
//    return m_states;
//}

StateMachine StmModel::saveSTMToPOU(const QString &stmid, const QString &filePath)
{
    // 获取状态机对象并检查其有效性
    StateMachine *stmPtr = getStateMachine(stmid);
    if (!stmPtr) {
        return StateMachine(); // 返回空对象表示失败
    }
    StateMachine stm = *stmPtr;

    // 打开文件以进行写入
    QFile file(filePath);
    if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
        return StateMachine(); // 文件打开失败，返回空对象
    }

    QXmlStreamWriter stream(&file);
    stream.setAutoFormatting(true);
    stream.writeStartDocument();

    // 开始写入StateMachineGE
    stream.writeStartElement("StateMachineGE");

    // 写入状态机的属性
    stream.writeAttribute("presentable", stm.redaceOid);
    stream.writeAttribute("name", stm.name);
    stream.writeAttribute("fileName", stm.filename);
    stream.writeAttribute("pouFileName", stm.poufilename);
    stream.writeAttribute("hierarchy", stm.hierarchy);
    stream.writeAttribute("projectId",stm.projectid);
    stream.writeAttribute("operatorId",stm.operatorOid);
    stream.writeAttribute("parentType",stm.parentType);
    stream.writeAttribute("parentOid",stm.parentOid);

    // 写入注释
    stream.writeStartElement("comment");
    stream.writeStartElement("Comment");
    stream.writeAttribute("valueStr", stm.comment);
    stream.writeEndElement();
    stream.writeEndElement(); // 结束comment

    // 开始写入状态列表
    stream.writeStartElement("data");
    for (int i = 0; i < stm.statelist.size(); i++) {
        State state = m_states.value(stm.statelist.at(i));
        stream.writeStartElement("StateGE");

        // 写入StateGE属性
        stream.writeAttribute("presentable", state.redaceOid);
        stream.writeAttribute("Text", state.name);
        stream.writeAttribute("initial", state.initial ? "true" : "false");
        stream.writeAttribute("final", state.final ? "true" : "false");
        stream.writeAttribute("hierarchy", state.hierarchy);

        // 写入状态注释
        stream.writeStartElement("comment");
        stream.writeStartElement("Comment");
        stream.writeAttribute("valueStr", state.comment);
        stream.writeEndElement();
        stream.writeEndElement(); // 结束comment

        // 写入位置
        stream.writeStartElement("position");
        stream.writeStartElement("point");
        stream.writeAttribute("x", QString::number(state.ge.rect.x()));
        stream.writeAttribute("y", QString::number(state.ge.rect.y()));
        stream.writeEndElement();
        stream.writeEndElement(); // 结束position

        // 写入大小
        stream.writeStartElement("size");
        stream.writeStartElement("Size");
        stream.writeAttribute("width", QString::number(state.ge.rect.width()));
        stream.writeAttribute("height", QString::number(state.ge.rect.height()));
        stream.writeEndElement();
        stream.writeEndElement(); // 结束size

        // 写入状态的转换信息
        stream.writeStartElement("transitions");
        writeTransitions(stream, state.trans_strong, "Strong");
        writeTransitions(stream, state.trans_weak, "Weak");
        writeTransitions(stream, state.trans_sync, "Synchro");
        stream.writeEndElement();//结束transitions

        // 写入state的Diagram信息
        stream.writeStartElement("diagrams");
        for(auto item:state.pouList)
        {
            stream.writeStartElement("NetDiagram");
            stream.writeAttribute("name", item.name);
            stream.writeAttribute("oid", item.oid);
            stream.writeEndElement();//结束NetDiagram
        }
        stream.writeEndElement();//结束diagrams

        //写入状态内嵌套的状态机信息
        stream.writeStartElement("StateMachines");
        for(auto item:state.stmList)
        {
            stream.writeStartElement("StateMachineRef");
            stream.writeAttribute("oid", item);
            auto stm=m_stms.value(item);
            stream.writeAttribute("name", stm.name);
            stream.writeAttribute("filepath", "/POUs/"+stm.hierarchy+"/"+stm.poufilename);
            stream.writeEndElement();//结束StateMachineRef
        }
        stream.writeEndElement();//结束StateMachines

        stream.writeEndElement(); // 结束StateGE
    }
    stream.writeEndElement(); // 结束data
    stream.writeEndElement(); // 结束StateMachineGE

    // 结束文档写入
    stream.writeEndDocument();
    file.close();

    // 检查写入是否有错误
    if (stream.hasError()) {
        return StateMachine(); // 写入过程中发生错误，返回空对象
    }

    return stm; // 成功返回保存的状态机对象
}

void StmModel::writeTransitions(QXmlStreamWriter &stream, const QVector<QString> &transList, const QString &kind)
{
    for (int i = 0; i < transList.size(); i++) {
        Transition transition = m_trans.value(transList.at(i));
        stream.writeStartElement("TransitionGE");

        // 写入TransitionGE的属性
        stream.writeAttribute("presentable", transition.oid);
        stream.writeAttribute("kind", kind);

        // 写入历史类型
        switch (transition.history) {
        case 0:
            stream.writeAttribute("history", "Restart");
            break;
        case 1:
            stream.writeAttribute("history", "Resume");
            break;
        }

        // 写入转换的路径
        stream.writeStartElement("position");
        for (int j = 0; j < transition.ge.path.size(); j++) {
            stream.writeStartElement("Point");
            stream.writeAttribute("x", QString::number(transition.ge.path[j].x()));
            stream.writeAttribute("y", QString::number(transition.ge.path[j].y()));
            stream.writeEndElement();
        }
        stream.writeEndElement(); // 结束position

        // 写入目标信息
        stream.writeStartElement("target");
        stream.writeAttribute("oid", transition.target);
        stream.writeEndElement(); // 结束target

        // 写入条件和操作的行
        stream.writeStartElement("rows");
        stream.writeStartElement("Condition");
        stream.writeAttribute("Text", transition.rawConditon().toHtmlEscaped());
        stream.writeEndElement(); // 结束Condition
        stream.writeStartElement("Action");
        stream.writeAttribute("Text", transition.rawAction().toHtmlEscaped());
        stream.writeEndElement(); // 结束Action
        stream.writeEndElement(); // 结束rows

        stream.writeEndElement(); // 结束TransitionGE
    }
}


void StmModel::loadPOUXML(const QString &filePath)
{
    StateMachine stm;
    int index = filePath.indexOf("/POUs");
    QString parentPath = filePath.left(index);
    stm.projectpath=parentPath;
    QFile file(filePath);
    if(!file.open(QFile::ReadOnly| QIODevice::Text)){
        qDebug()<<"Open FILE failed";
        return;
    }
    QTextStream stream(&file);
    QString xmlContent = stream.readAll();
    file.close();
    QDomDocument doc;
    if(!doc.setContent(xmlContent)){

        return;
    }

    QDomElement root=doc.documentElement();//StateMachineGE
    stm.name=root.attribute("name");
    stm.redaceOid = root.attribute("presentable");
    stm.filename=root.attribute("fileName");
    stm.poufilename=root.attribute("pouFileName");
    stm.hierarchy=root.attribute("hierarchy");
    stm.projectid=root.attribute("projectId");
    stm.operatorOid=root.attribute("operatorId");
    stm.parentType=root.attribute("parentType");
    stm.parentOid=root.attribute("parentOid");

    //QDomNode node=root.firstChild();//presentationElements

    stm.comment=root.namedItem("comment").firstChildElement().attribute("valueStr");

    QDomNodeList statelist = root.namedItem("data").childNodes();//存在的若干个状态列表
    for(int j = 0; j < statelist.size(); j++){
        POU pou;
        State state;
        QDomElement element = statelist.at(j).toElement();
        //单个状态
        state.parentid=stm.redaceOid;
        pou.filePath = element.attribute("hierarchy");
        state.redaceOid=element.attribute("presentable");
        state.ge.present=element.attribute("presentable");
        state.initial=(element.attribute("initial") == "true");
        if(state.initial)
        {
            stm.initstate=state.scadeOid;
        }

        state.final=(element.attribute("final") == "true");
        state.name=element.attribute("Text");
        state.hierarchy=element.attribute("hierarchy");
        state.comment=element.namedItem("comment").firstChildElement().attribute("valueStr");
        state.ge.rect.setX(element.namedItem("position").firstChildElement().attribute("x").toInt());
        state.ge.rect.setY(element.namedItem("position").firstChildElement().attribute("y").toInt());
        state.ge.rect.setWidth(element.namedItem("size").firstChildElement().attribute("width").toInt());
        state.ge.rect.setHeight(element.namedItem("size").firstChildElement().attribute("height").toInt());

        QDomNodeList transitionlist = element.namedItem("transitions").childNodes();//存在的若干个迁移列表
        for(int m = 0; m < transitionlist.size(); m++){
            Transition transition;
            QDomElement element = transitionlist.at(m).toElement();
            //开始强迁移

            //Transition transition;
            transition.prior=m+1;
            transition.oid=element.attribute("presentable");
            transition.source=state.scadeOid;
            transition.ge.present=element.attribute("presentable");
            if (element.attribute("history")=="Restart") {
                transition.history=RESTART;
            }else {
                transition.history=RESUME;
            }

            if(element.attribute("kind")=="Strong")
            {
                transition.kind = STRONG;
                state.trans_strong.append(transition.oid);
            }
            else if(element.attribute("kind")=="Weak")
            {
                transition.kind = WEAK;
                state.trans_weak.append(transition.oid);
            }
            else if (element.attribute("kind")=="Synchro") {
                transition.kind = SYNCHRO;
                state.trans_sync.append(transition.oid);
            }

            QDomNodeList positionlist = element.namedItem("position").childNodes();//存在的若干个point
            for (int n=0;n<positionlist.size();n++) {
                QDomElement element = positionlist.at(n).toElement();
                QPoint point(element.attribute("x").toInt(),element.attribute("y").toInt());
                transition.ge.path.append(point);
            }
            transition.target=element.namedItem("target").toElement().attribute("oid");
            QString cond = element.namedItem("rows").namedItem("Condition").toElement().attribute("Text");
            QString action = element.namedItem("rows").namedItem("Action").toElement().attribute("Text");
            transition.setRawConditon(cond);
            transition.setRawAction(action);

            addTrans(transition);

        }//所有迁移结束

        QDomElement diagramsEle=element.namedItem("diagrams").toElement();
        QDomNodeList diagramsChildNodes=diagramsEle.childNodes();

        for(int i=0;i<diagramsChildNodes.size();i++)
        {
            QDomElement diaItem=diagramsChildNodes.at(i).toElement();
            //StateMachineDefine::POU pou;
            pou.name=diaItem.attribute("name");
            pou.oid=diaItem.attribute("oid");

            state.pouList.append(pou);
        }

        QDomElement stateMachinesEle=element.namedItem("StateMachines").toElement();
        QDomNodeList stateMachinesChildNodes=stateMachinesEle.childNodes();

        for(int i=0;i<stateMachinesChildNodes.size();i++)
        {
            QDomElement stmItem=stateMachinesChildNodes.at(i).toElement();
            QString stmOid=stmItem.attribute("oid");
            QString stmName=stmItem.attribute("name");
            QString stmPouFilePath=stm.projectpath+"/"+stmItem.attribute("filepath");

            loadPOUXML(stmPouFilePath);

            state.stmList.append(stmOid);
        }

        stm.statelist.append(state.scadeOid);
        addState(state.redaceOid,state);
    }

    //statemachines_.insert(stm.oid,stm);
    addStateMachine(stm.redaceOid,stm);

    return;
}

